#!/usr/bin/env python
#
# Copyright 2010 Steve Leach
# Licensed under the MIT license: http://www.opensource.org/licenses/mit-license.php
#

import logging
from datetime import datetime, timedelta

from google.appengine.ext import db
from google.appengine.api import quota
from google.appengine.api import memcache

from eveoperation import EveOperation, Pilot, MultiPay, Corp, AssistType, Assist, WaitingPilot, PilotRole, SiteSig
from eveoperation import get_main_name
from sites import get_site_names
from handlers import BaseHandler, EveOpsHandler, get_cached_query, cache_query
from formatting import format_thousands
from evedata import EveData, get_eve_data

def add_ops_mappings(mappings):
	"""
	Adds the mappings for the ops handlers.
	"""
	mappings.append(('/', ListHandler))
	mappings.append(('/listops', ListHandler))
	mappings.append(('/newop', NewOpHandler))
	mappings.append(('/viewop', ViewOpHandler))
  	mappings.append(('/editop', EditOpHandler))
  	mappings.append(('/submitop', SubmitHandler))
	mappings.append(('/joinop', AddPilotHandler))
	mappings.append(('/addpilot', AddPilotHandler))
	mappings.append(('/submitpilot', AddPilotHandler))
  	mappings.append(('/addassist', AssistHandler))
  	mappings.append(('/claimassist', ClaimAssistHandler))
	mappings.append(('/waitlist', WaitListHandler))
	mappings.append(('/submitwaiting', SubmitWaitListHandler))
	mappings.append(('/opsdata', OpsDataHandler))
  	mappings.append(('/lockop', LockOpHandler))
  	mappings.append(('/removepilot', RemovePilotHandler))
  	mappings.append(('/deleteop', DeleteOpHandler))
	mappings.append(('/payop', PayOpHandler))
	mappings.append(('/setrole', SetRoleHandler))
	mappings.append(('/sitesigs', SiteSigListHandler))
	mappings.append(('/editsitesig', EditSiteSigHandler))

class BaseOpHandler(BaseHandler):

	def get_op(self):
		"""
		Checks the http request params to try and identify which eve operation
		should be used.
		"""
		if self.request.get('key'):
			op = db.get(self.request.get('key'))
		elif self.request.get('id'):
			op = EveOperation.get_by_id(int(self.request.get('id')))
		return op

	def get_pilot(self):
		return Pilot.gql('WHERE char_name = :1', self.eve_data.char_name).get()
	
def get_op(request):
	"""
	Checks the http request params to try and identify which eve operation
	should be used.
	"""
	if request.get('key'):
		op = db.get(request.get('key'))
	elif request.get('id'):
		op = EveOperation.get_by_id(int(request.get('id')))
	return op

def is_fc(eve_data, op):
	"""
	Returns true if the current user is the Fleet Commander
	for the specified operation.
	"""
	return eve_data.char_name == op.fc

def random_name():
	first = random.choice(['Big','Small','Heavy','Thin','Angry','Fast','Slow','Long','Short','Tall','Wide'])
	second = random.choice(['Blue','Red','Black','White','Hungry','Angry','Smooth','Silent'])
	third = random.choice(['Ship','Pirate','Planet','Star','Cannon','Laser','Pod','Gate','Station','Fleet'])
	return first + ' ' + second + ' ' + third

class ListHandler(BaseHandler):
	"""
	Http request handler for the list operations page.
	"""
	def do_get(self):
		pilots = Pilot.gql('WHERE char_name = :1', self.eve_data.char_name)
		if pilots.count() == 0:
			pilot = Pilot()
			pilot.char_name = self.eve_data.char_name
			pilot.char_id = self.eve_data.char_id
			pilot.put()
					
		show_paid = self.request.get('showpaid')

		if self.request.get('cache') == 'false':
			clear_ops_cache()			

		cache_hit = False	

		if show_paid:
			ops2 = EveOperation.gql('WHERE deleted_op = False ORDER BY op_time DESC')
		else:
			# Use the cached version if it is available
			ops2 = get_cached_query("ops_list")
			if ops2 is None:
				# If not cached, get from datastore and cache it
				logging.info("Ops list cache miss")
				ops2 = EveOperation.gql('WHERE deleted_op = False AND paid = False ORDER BY op_time DESC').fetch(1000)
				cache_query(ops2, "ops_list", 30*60) # 30 min cache expiry
			else:
				logging.debug("Ops list cache hit")
				cache_hit = True				

		pilot_name = get_main_name(self.eve_data.char_name)

		pilot_isk = 0
		corp = Corp.gql('WHERE corp_id = :1', self.eve_data.corp_id).get()
		if corp:
			for op in ops2:
				if pilot_name in op.pilots:
					isk = (corp.ave_op_isk * 0.9) / len(op.pilots)
					pilot_isk += isk * op.site_count

		self.pagevalues['ops'] = ops2
		self.pagevalues['auto_refresh'] = True
		self.pagevalues['pilot_isk'] = pilot_isk		
		self.pagevalues['pilot_isk_000'] = format_thousands(int(pilot_isk))
		self.pagevalues['cache_hit'] = cache_hit
		self.pagevalues['main_name'] = pilot_name
  	
  		self.show_page('listops.html')

class PilotInfo():
	pass

class AssistSummary():
	pass

class ViewOpHandler(BaseHandler):
	"""
	Http request handler for view operartion.
	"""
	def do_get(self):
		op = get_op(self.request)
		pilot_is_fc = is_fc(self.eve_data, op)

		start = quota.get_request_cpu_usage()

		assist_types = AssistType.all()

		assist_map = {}
		assists = Assist.gql('WHERE op_ref = :1', op)
		for assist_data in assists:
			key = assist_data.pilot + "/" + assist_data.assist_kind
			assist_map[key] = assist_data

		pilot_info = []
		for p in sorted(op.pilots):
			pi = PilotInfo()
			pi.name = p
			pi.assists = []
			pi.is_current = (pi.name == self.eve_data.char_name)
			role = PilotRole.gql('WHERE op_id = :1 AND pilot_name = :2', op.key().id(), pi.name).get()
			if role:
				pi.role = role.role
			for assist_type in assist_types:
				assist = AssistSummary()
				key = pi.name + "/" + assist_type.name
				if key in assist_map:
					assist_data = assist_map[key]
					assist.offered = assist_data.quantity - len(assist_data.assigned_to)
					assignees = ''
					for assignee in assist_data.assigned_to:
						assignees = assignees + assignee + ', '
					assist.assignees = assignees
					assist.claimed = len(assist_data.assigned_to)
				else:					
					assist.offered = 0
					assist.claimed = 0
				assist.name = assist_type.name
				pi.assists.append(assist)
			pilot_info.append(pi)
	
		self.pagevalues['op'] = op
		self.pagevalues['is_fc'] = pilot_is_fc
		self.pagevalues['can_edit'] = pilot_is_fc
		self.pagevalues['assist_types'] = assist_types
		self.pagevalues['pilot_info'] = pilot_info

		pilot = Pilot.gql('WHERE char_name = :1', self.eve_data.char_name).get()
		if pilot:
			self.pagevalues['can_edit'] = pilot_is_fc or pilot.is_director or pilot.is_dev
  	
		end = quota.get_request_cpu_usage()		

		self.show_page('viewop.html')

class EditOpHandler(BaseHandler):
  """
  Http request handler for the edit operation page.
  """
  def do_get(self):
	op = get_op(self.request)

	can_edit = is_fc(self.eve_data, op)
	pilot = Pilot.gql('WHERE char_name = :1', self.eve_data.char_name).get()
	if pilot:
		can_edit = can_edit or pilot.is_director or pilot.is_dev

	if can_edit:
	   	self.pagevalues['op'] = op
		self.pagevalues['is_fc'] = is_fc(self.eve_data, op)
	  	self.pagevalues['site_names'] = get_site_names()
	  	
		self.show_page('editop.html')
	else:
		self.redirect('/error?msg=1005')

class AssistHandler(BaseHandler):
	def do_get(self):
		op = get_op(self.request)
		pilot_name = self.eve_data.char_name
		assist_type = self.request.get('kind')

		assist = Assist.gql('WHERE op_ref = :1 AND pilot = :2 AND assist_kind = :3', op, pilot_name, assist_type).get()
		if not assist:
			assist = Assist(op_ref=op, pilot=pilot_name, assist_kind=assist_type)
		assist.quantity += int(self.request.get('value'))
		if assist.quantity < 0:
			assist.quantity = 0
		assist.put()

		self.redirect('/viewop?id=' + str(op.key().id()) )

class ClaimAssistHandler(BaseHandler):
	def do_get(self):
		op = get_op(self.request)
		pilot_name = self.eve_data.char_name
		assist_type = self.request.get('kind')

		assist = Assist.gql('WHERE op_ref = :1 AND pilot = :2 AND assist_kind = :3', op, self.request.get('pilot'), assist_type).get()

		if assist:
			if self.request.get('clear') == 'True':
				assist.assigned_to = []
			else:
				if not pilot_name in assist.assigned_to:
					assist.assigned_to.append(pilot_name)
			assist.put()

		self.redirect('/viewop?id=' + str(op.key().id()) )

class WaitListHandler(BaseHandler):
	def do_get(self):
		d = timedelta(minutes=60)
		cutoff = datetime.now() - d
		list = WaitingPilot.gql('WHERE waiting_since > :1 ORDER BY waiting_since', cutoff)
		self.pagevalues['waiting_list'] = list
		self.show_page('waitinglist.html')

class SubmitWaitListHandler(BaseHandler):
	def do_post(self):
		pilot = WaitingPilot(pilot_name=self.request.get('pilot_name'))
		pilot.location = self.request.get('location')
		pilot.capability = self.request.get('capability')
		pilot.put()
		self.redirect('/waitlist' )

class NewOpHandler(BaseHandler):
	def do_get(self):
		# On GET, display the form
		self.pagevalues['op_fc'] = self.eve_data.char_name
		self.pagevalues['site_names'] = get_site_names()
		self.pagevalues['site_type'] = 'Other'
		self.show_page('newop.html')

	def do_post(self):
		# On POST, create the Op
		op = EveOperation(name=self.request.get('name'))
		op.op_type = self.request.get('op_type')
		op.fc = self.request.get('fc')
		if op.fc != '{unknown}':
			op.pilots.append(op.fc)
		op.corp_name = self.eve_data.corp_name
		op.corp_id = self.eve_data.corp_id
		op.system = self.eve_data.system_name
		op.site_type = self.request.get('site_type')
		if self.eve_data.system_name:
			op.system = self.eve_data.system_name
		else:
			op.system = 'Unknown'
		key = op.put()

		clear_ops_cache()
		
		self.redirect('/viewop?id='+ str(op.key().id()))

def clear_ops_cache():
	memcache.delete("ops_list")

class OpsDataHandler(BaseHandler):
	def write_value(self,value):
		self.response.out.write(value)
		self.response.out.write('\t')

	def do_get(self):
		self.response.headers['Content-Type'] = 'text/tab-separated-values'
		#self.response.headers['Content-Type'] = 'text/plain'

		self.write_value('Name')
		self.write_value('Time')
		self.write_value('Pilots')
		self.write_value('FC')
		self.write_value('ISK')
		self.write_value('Locked')
		self.write_value('Paid')
		self.write_value('Site')
		self.write_value('System')
		self.write_value('PayStrat')
		self.write_value('PilotList')
		self.response.out.write('\n')

		ops = EveOperation.gql('WHERE deleted_op = False ORDER BY op_time DESC')

		for op in ops:
			self.write_value(op.name)
			self.write_value(op.op_time.isoformat(' '))
			self.write_value(len(op.pilots))
			self.write_value(op.fc)
			self.write_value(op.isk)
			self.write_value(op.locked)
			self.write_value(op.paid)
			self.write_value(op.site_type)
			self.write_value(op.system)
			self.write_value(op.pay_strategy)
			pilot_list = ''
			for pilot in op.pilots:
				pilot_list += pilot + ';'
			self.write_value(pilot_list)			
			self.response.out.write('\n')


class LockOpHandler(BaseHandler):
  def do_get(self):
	op = get_op(self.request)
	can_edit = is_fc(self.eve_data, op)

	pilot = Pilot.gql('WHERE char_name = :1', self.eve_data.char_name).get()
	if pilot:
		can_edit = can_edit or pilot.is_director or pilot.is_dev

	if can_edit:
		op.locked = (self.request.get('locked') == 'True')
		op.put()

		clear_ops_cache()
	  	
		self.redirect('/viewop?id='+str(op.key().id()))
	else:
		self.redirect('/error?msg=1005')

class RemovePilotHandler(BaseHandler):
	def do_get(self):  
		op = get_op(self.request)
		pilot_name = self.request.get('pilot')
		op.pilots.remove(pilot_name)
		op.put()

		logging.info('Pilot %s removed from op %s by %s' % (pilot_name, op.name, self.eve_data.char_name))

		clear_ops_cache()

		self.redirect('/viewop?id='+ str(op.key().id()))

class DeleteOpHandler(BaseHandler):

	def do_post(self):
		if self.request.get('submit') == 'Yes':
			op = EveOperation.get_by_id(int(self.request.get('key')))
			op.deleted_op = True
			op.put()

			logging.info('Op %s deleted by %s' % (op.name, self.eve_data.char_name))

		clear_ops_cache()

		self.redirect('/listops')

	def get(self):  
		self.do_post()

def add_pilot_to_op(op_key, pilot_name):
	op = db.get(op_key)
	op.add_pilot(pilot_name)
	op.put()

class AddPilotHandler(BaseOpHandler):
	def do_get(self):
		op = self.get_op()

		# Use the supplied Eve Data to get the default name
		pilot_name = self.eve_data.char_name
		if pilot_name:
			# Then see if the current char is an alt, and use the main instead
			pilot = Pilot.gql('WHERE char_name = :1', pilot_name).get()
			if pilot:
				if pilot.main_char:
					pilot_name = pilot.main_char
		
		self.pagevalues['op'] = op
		self.pagevalues['default_name'] = pilot_name
	  	self.show_page('addpilot.html')

	def do_post(self):
	  	op = self.get_op()

		if op.locked:
			self.redirect('/error?msg=1004')		
		else:
			try:
				pilot_name = self.request.get('pilot')
				db.run_in_transaction(add_pilot_to_op, op.key(), pilot_name)

				# Remove pilot from waiting list
				waiting = WaitingPilot.gql('Where pilot_name = :1', pilot_name)
				for w in waiting:
					w.delete()

				# Update last op time for pilot
				pilot = Pilot.gql("Where char_name = :1", pilot_name).get()
				if pilot:
					pilot.last_op = op.op_time
					pilot.put()

				clear_ops_cache()

				self.redirect('/viewop?id='+ str(op.key().id()))
			except:
				logging.warning('Pilot ' + self.request.get('pilot') + ' already on op ' + op.name)
				self.redirect('/error?msg=1001')		
		
class SubmitHandler(BaseOpHandler):
	def do_post(self):
	  	op = self.get_op()
	  	op.name = self.request.get('name')
	  	op.op_type = self.request.get('op_type')
		op.isk = int(self.request.get('isk'))
		op.fc = self.request.get('fc')
		op.site_type = self.request.get('site_type')
		op.locked = self.request.get('locked') == 'locked'
		op.site_count = int(self.request.get('site_count'))
		op.put()
		
		clear_ops_cache()

		self.redirect('/viewop?id='+str(op.key().id()))

class PayOpHandler(BaseOpHandler):
	def do_get(self):  
		op = self.get_op()	  			

		if self.request.get('isk'):
			op.isk = int(self.request.get('isk'))
			op.paid = self.request.get('paid') == 'paid'
			op.put()

		self.pagevalues['op'] = op
		self.pagevalues['pilot'] = self.get_pilot()

		self.show_page('payop.html')

	def do_post(self):
		op = self.get_op()

		op.ancient_coord_count = int(self.request.get('ancient_coord_count'))
		op.neural_net_count = int(self.request.get('neural_net_count'))
		op.data_lib_count = int(self.request.get('data_lib_count'))
		op.drone_ai_count = int(self.request.get('drone_ai_count'))
		op.salvage_isk = int(self.request.get('salvage_isk'))
		op.corp_tax = int(self.request.get('corp_tax'))
		op.pay_strategy = int(self.request.get('pay_strategy'))

		pilot = self.get_pilot()
		pilot.ancient_coord_isk = int(self.request.get('ancient_coord_isk'))
		pilot.neural_net_isk = int(self.request.get('neural_net_isk'))
		pilot.data_lib_isk = int(self.request.get('data_lib_isk'))
		pilot.drone_ai_isk = int(self.request.get('drone_ai_isk'))
		pilot.payop_next = self.request.get('next')
		pilot.put()

		if op.salvage_isk == 0:
			op.isk = int(self.request.get('isk'))
	
		op.paid = self.request.get('paid') == 'paid'

		op.calc_op_isk(pilot)
		op.put()

		clear_ops_cache()

		if self.request.get("next") == "multipay":
			self.redirect('/multipay')
		else:
			self.redirect('/payop?id='+ str(op.key().id()))
	
class SetRoleHandler(BaseOpHandler):
	def do_get(self):
		self.pagevalues['op'] = self.get_op()
		self.pagevalues['pilot'] = self.request.get('pilot')

		self.show_page('setrole.html')

	def do_post(self):
		op = self.get_op()

		pilot = self.request.get('pilot')

		roles = PilotRole.gql('WHERE op_id = :1 AND pilot_name = :2', op.key().id(), pilot)
		for role in roles:
			role.delete()

		new_role = self.request.get('role')

		if not new_role == 'None':
			role = PilotRole(op_id=op.key().id(), pilot_name = pilot, role=new_role)
			role.op_date = op.op_date
			role.put()

		self.redirect('/viewop?id='+ str(op.key().id()))

class SiteSigListHandler(BaseOpHandler):
	def do_get(self):
		if SiteSig.all().count() == 0:
			sig = SiteSig(system='J105934', sig_code='ABC')
			sig.site_type = 'The Mirror'
			sig.expires_day = 'Wed'
			sig.put()

		if self.request.get('expired') == 'true':
			self.pagevalues['sigs'] = SiteSig.all() 
		else:
			self.pagevalues['sigs'] = SiteSig.gql('WHERE expired = False')

		self.show_page('sitesigs.html')

class FakeSiteSig:
	pass

class EditSiteSigHandler(BaseOpHandler):
	def do_get(self):
		if self.request.get('new_sig'):
			sig = FakeSiteSig()
			sig.system = self.eve_data.system_name
			sig.fake = True
		elif self.request.get('id'):
			sig = SiteSig.get_by_id( int(self.request.get('id')) )

		self.pagevalues['sig'] = sig
		self.show_page('sitesig.html')

	def do_post(self):
		if self.request.get('id'):
			sig = SiteSig.get_by_id( int(self.request.get('id')) )
		else:
			sig = SiteSig(system=self.request.get('system'), sig_code=self.request.get('sig_code'))

		sig.system = self.request.get('system').upper()
		sig.sig_code = self.request.get('sig_code').upper()
		sig.site_type = self.request.get('site_type')
		sig.expires_day = self.request.get('expires_day')
		sig.expired = (self.request.get('expired') == 'expired')
		sig.started = (self.request.get('started') == 'started')
		sig.put()

		self.redirect('/sitesigs')

#
# End
#
